/**
 * 
 */
package pt.mleiria.crypto.skip;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.KeyAgreement;

import org.apache.commons.codec.binary.Base64;

/**
 * @author NB13712
 *
 */
public class SkipServer {

	public static void main(String[] args) throws Exception{
		int port = Integer.parseInt(args[0]);
		
		// Create a Diffie-Hellman key pair.
		KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH");
		kpg.initialize(Skip.sDHParameterSpec);
		KeyPair keyPair = kpg.genKeyPair();
		
		// Wait for a connection.
		ServerSocket serverSocket = new ServerSocket(port);
		System.out.println("Listening on port " + port + "...");
		Socket socket = serverSocket.accept();
		DataOutputStream out = new DataOutputStream(socket.getOutputStream());
		DataInputStream in = new DataInputStream(socket.getInputStream());
		/*
		 * First, the client will send us an encoded Diffie-Hellman public key as an array of bytes. A KeyFactory
		 * is used to reconstruct the key.
		 * Receive a public key.
		 */
		byte[] keyBytes = new byte[in.readInt()];
		in.readFully(keyBytes);
		KeyFactory kf = KeyFactory.getInstance("DH");
		X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(keyBytes);
		PublicKey theirPublicKey = kf.generatePublic(x509Spec);
		/*
		 * Then we send our public key to the client.
		 * Send the public key.
		 */
		keyBytes = keyPair.getPublic().getEncoded();
		out.writeInt(keyBytes.length);
		out.write(keyBytes);
		/*
		 * Now we can calculate the secret value, using our private key and the client's public key. The secret
		 * value is as long as the modulus used to generate the Diffie-Hellman keys. In this case, the secret value
		 * is 1024 bits long.
		 * Generate the secret value
		 */
		KeyAgreement ka = KeyAgreement.getInstance("DH");
		ka.init(keyPair.getPrivate());
		ka.doPhase(theirPublicKey, true);
		byte[] secret = ka.generateSecret();
		// Clean up.
		out.close();
		in.close();
		Base64 b64 = new Base64();
		System.out.println(new String(b64.encode(secret), "UTF-8"));
		
	}
}
